const crypto = require('crypto')
/*!
 * 生成随机字符串
 */
const createNonceStr = function () {
  return Math.random().toString(36).substr(2, 15)
}

/*!
 * 生成时间戳
 */
const createTimestamp = function () {
  return parseInt(new Date().getTime() / 1000, 0) + ''
}

/*!
 * 排序查询字符串
 */
const raw = function (args) {
  var keys = Object.keys(args)
  keys = keys.sort()
  var newArgs = {}
  keys.forEach(function (key) {
    newArgs[key.toLowerCase()] = args[key]
  })

  var string = ''
  for (var k in newArgs) {
    string += '&' + k + '=' + newArgs[k]
  }
  return string.substr(1)
}

/*!
 * 签名算法
 *
 * @param {String} nonceStr 生成签名的随机串
 * @param {String} jsapi_ticket 用于签名的jsapi_ticket
 * @param {String} timestamp 时间戳
 * @param {String} url 用于签名的url，注意必须与调用JSAPI时的页面URL完全一致
 */
const sign = function (nonceStr, jsapi_ticket, timestamp, url) {
  var ret = {
    jsapi_ticket: jsapi_ticket,
    nonceStr: nonceStr,
    timestamp: timestamp,
    url: url
  }
  var string = raw(ret)
  var shasum = crypto.createHash('sha1')
  shasum.update(string)
  return shasum.digest('hex')
}

/*!
 * 卡券card_ext里的签名算法
 *
 * @name signCardExt
 * @param {String} api_ticket 用于签名的临时票据，获取方式见2.获取api_ticket。
 * @param {String} card_id 生成卡券时获得的card_id
 * @param {String} timestamp 时间戳，商户生成从1970 年1 月1 日是微信卡券接口文档00:00:00 至今的秒数,即当前的时间,且最终需要转换为字符串形式;由商户生成后传入。
 * @param {String} code 指定的卡券code 码，只能被领一次。use_custom_code 字段为true 的卡券必须填写，非自定义code 不必填写。
 * @param {String} openid 指定领取者的openid，只有该用户能领取。bind_openid 字段为true 的卡券必须填写，非自定义code 不必填写。
 * @param {String} balance 红包余额，以分为单位。红包类型（LUCKY_MONEY）必填、其他卡券类型不必填。
 */
const signCardExt = function (api_ticket, card_id, timestamp, code, openid, balance) {
  var values = [api_ticket, card_id, timestamp, code || '', openid || '', balance || '']
  values.sort()

  var string = values.join('')
  var shasum = crypto.createHash('sha1')
  shasum.update(string)
  return shasum.digest('hex')
}

module.exports = function (token) {
  const get_ticket = async (type = 'jsapi') => {
    const cacheName = `wechat_ticket_${type}_${this.appid}`
    let ticket = await think.cache(cacheName)
    if (!ticket) {
      const d = await yy.http.get(`https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${token}&type=${type}`)
      yy.log.info(d)
      if (d.errcode === 0) {
        await think.cache(cacheName, d.ticket, {type: 'file', file: {timeout: 6500 * 1000}})
        ticket = d.ticket
      }else{
        return d
      }
    }
    return ticket
  }

  /**
     * @param url
     * @param debug
     * @param jsApiList
     * @returns {{debug: (*|boolean|debug), url: (*|string), appId: *, timestamp, nonceStr, signature, jsApiList: (*|string[])}}
     */
  const get_js = async (param) => {
    const nonceStr = createNonceStr()
    const jsAPITicket = await get_ticket('jsapi')
    const timestamp = createTimestamp()
    const url = param.url || ''
    const signature = sign(nonceStr, jsAPITicket, timestamp, url)
    const debug = param.debug || false
    const jsApiList = param.jsApiList || [
      'checkJsApi',
      'onMenuShareTimeline',
      'onMenuShareAppMessage',
      'onMenuShareQQ',
      'onMenuShareWeibo',
      'hideMenuItems',
      'showMenuItems',
      'hideAllNonBaseMenuItem',
      'showAllNonBaseMenuItem',
      'translateVoice',
      'startRecord',
      'stopRecord',
      'onRecordEnd',
      'playVoice',
      'pauseVoice',
      'stopVoice',
      'uploadVoice',
      'downloadVoice',
      'chooseImage',
      'previewImage',
      'uploadImage',
      'downloadImage',
      'getNetworkType',
      'openLocation',
      'getLocation',
      'hideOptionMenu',
      'showOptionMenu',
      'closeWindow',
      'scanQRCode',
      'chooseWXPay',
      'openProductSpecificView',
      'addCard',
      'chooseCard',
      'openCard'
    ]
    const result = {
      debug: debug,
      url: url,
      appId: this.appid,
      timestamp: timestamp,
      nonceStr: nonceStr,
      signature: signature,
      jsApiList: jsApiList
    }

    // 判断beta参数是否存在，微信硬件开发用
    // beta: true
    // 开启内测接口调用，注入wx.invoke方法
    if (param.beta) {
      result.beta = param.beta
    }
    return result
  }
  /**
     * 获取卡券jssdk
     * @param card_id
     * @param code
     * @param openid
     * @param balance
     * @returns {{timestamp, signature}}
     */
  const get_card = async (param) => {
    const apiTicket = await get_ticket('wx_card')
    const timestamp = createTimestamp()
    const signature = signCardExt(apiTicket, param.card_id, timestamp, param.code, param.openid, param.balance)
    const result = {
      timestamp: timestamp,
      signature: signature
    }

    result.code = param.code || ''
    result.openid = param.openid || ''

    if (param.balance) {
      result.balance = param.balance
    }
    return result
  }

  return {
    get_ticket,
    get_js,
    get_card
  }
}
